//! uis for egui types.
use crate::*;

impl Widget for &epaint::Texture {
    fn ui(self, ui: &mut Ui) -> Response {
        use epaint::Mesh;

        ui.vertical(|ui| {
            // Show font texture in demo Ui
            ui.label(format!(
                "Texture size: {} x {} (hover to zoom)",
                self.width, self.height
            ));
            if self.width <= 1 || self.height <= 1 {
                return;
            }
            let mut size = vec2(self.width as f32, self.height as f32);
            if size.x > ui.available_width() {
                size *= ui.available_width() / size.x;
            }
            let (rect, response) = ui.allocate_at_least(size, Sense::hover());
            let mut mesh = Mesh::default();
            mesh.add_rect_with_uv(
                rect,
                [pos2(0.0, 0.0), pos2(1.0, 1.0)].into(),
                Color32::WHITE,
            );
            ui.painter().add(Shape::mesh(mesh));

            let (tex_w, tex_h) = (self.width as f32, self.height as f32);

            response
                .on_hover_cursor(CursorIcon::ZoomIn)
                .on_hover_ui_at_pointer(|ui| {
                    if let Some(pos) = ui.input().pointer.latest_pos() {
                        let (_id, zoom_rect) = ui.allocate_space(vec2(128.0, 128.0));
                        let u = remap_clamp(pos.x, rect.x_range(), 0.0..=tex_w);
                        let v = remap_clamp(pos.y, rect.y_range(), 0.0..=tex_h);

                        let texel_radius = 32.0;
                        let u = u.at_least(texel_radius).at_most(tex_w - texel_radius);
                        let v = v.at_least(texel_radius).at_most(tex_h - texel_radius);

                        let uv_rect = Rect::from_min_max(
                            pos2((u - texel_radius) / tex_w, (v - texel_radius) / tex_h),
                            pos2((u + texel_radius) / tex_w, (v + texel_radius) / tex_h),
                        );
                        let mut mesh = Mesh::default();
                        mesh.add_rect_with_uv(zoom_rect, uv_rect, Color32::WHITE);
                        ui.painter().add(Shape::mesh(mesh));
                    }
                });
        })
        .response
    }
}

impl Widget for &mut epaint::text::FontDefinitions {
    fn ui(self, ui: &mut Ui) -> Response {
        ui.vertical(|ui| {
            for (text_style, (_family, size)) in self.family_and_size.iter_mut() {
                // TODO: radio button for family
                ui.add(
                    Slider::new(size, 4.0..=40.0)
                        .max_decimals(0)
                        .text(format!("{:?}", text_style)),
                );
            }
            crate::reset_button(ui, self);
        })
        .response
    }
}

impl Widget for &epaint::stats::PaintStats {
    fn ui(self, ui: &mut Ui) -> Response {
        ui.vertical(|ui| {
            ui.label(
                "egui generates intermediate level shapes like circles and text. \
            These are later tessellated into triangles.",
            );
            ui.add_space(10.0);

            ui.style_mut().body_text_style = TextStyle::Monospace;

            let epaint::stats::PaintStats {
                shapes,
                shape_text,
                shape_path,
                shape_mesh,
                shape_vec,
                clipped_meshes,
                vertices,
                indices,
            } = self;

            ui.label("Intermediate:");
            label(ui, shapes, "shapes").on_hover_text("Boxes, circles, etc");
            label(ui, shape_text, "text");
            label(ui, shape_path, "paths");
            label(ui, shape_mesh, "nested meshes");
            label(ui, shape_vec, "nested shapes");
            ui.add_space(10.0);

            ui.label("Tessellated:");
            label(ui, clipped_meshes, "clipped_meshes")
                .on_hover_text("Number of separate clip rectangles");
            label(ui, vertices, "vertices");
            label(ui, indices, "indices").on_hover_text("Three 32-bit indices per triangles");
            ui.add_space(10.0);

            // ui.label("Total:");
            // ui.label(self.total().format(""));
        })
        .response
    }
}

pub fn label(ui: &mut Ui, alloc_info: &epaint::stats::AllocInfo, what: &str) -> Response {
    ui.add(Label::new(alloc_info.format(what)).wrap(false))
}

impl Widget for &mut epaint::TessellationOptions {
    fn ui(self, ui: &mut Ui) -> Response {
        ui.vertical(|ui| {
            let epaint::TessellationOptions {
                pixels_per_point: _,
                aa_size: _,
                anti_alias,
                coarse_tessellation_culling,
                debug_paint_clip_rects,
                debug_paint_text_rects,
                debug_ignore_clip_rects,
            } = self;
            ui.checkbox(anti_alias, "Antialias")
                .on_hover_text("Turn off for small performance gain.");
            ui.collapsing("debug", |ui| {
                ui.checkbox(
                    coarse_tessellation_culling,
                    "Do coarse culling in the tessellator)",
                );
                ui.checkbox(debug_ignore_clip_rects, "Ignore clip rectangles");
                ui.checkbox(debug_paint_clip_rects, "Paint clip rectangles");
                ui.checkbox(debug_paint_text_rects, "Paint text bounds");
            });
        })
        .response
    }
}

impl Widget for &memory::Interaction {
    fn ui(self, ui: &mut Ui) -> Response {
        ui.vertical(|ui| {
            ui.label(format!("click_id: {:?}", self.click_id));
            ui.label(format!("drag_id: {:?}", self.drag_id));
            ui.label(format!("drag_is_window: {:?}", self.drag_is_window));
            ui.label(format!("click_interest: {:?}", self.click_interest));
            ui.label(format!("drag_interest: {:?}", self.drag_interest));
        })
        .response
    }
}
